In modern applications, permanently deleting records is often undesirable. Instead, developers prefer an approach that allows records to be marked as deleted without actually removing them from the database. This approach is known as "Soft Delete." In this blog post, we'll explore how to implement Soft Delete in a Spring Boot application using JPA for data persistence.
What is Soft Delete?
Soft Delete is a pattern where records in the database are not physically deleted but are instead marked as deleted. This is typically achieved by a deletedAt field in the database table. If this field is null, the record is considered active. If it's set to a timestamp, however, the record is considered deleted.
Benefits of Soft Delete
- Data Recovery: Deleted records can be easily restored.
- Preserve Integrity: Relationships with other tables remain intact, protecting data integrity.
- Audit Trail: The deletedAt field provides a built-in audit trail for the deletion of records.
Implementation in Spring Boot with JPA
Step 1: Creating the Base Entity
Let's start by creating a base entity that includes common attributes like createdAt, updatedAt, and deletedAt. This class will be inherited by all entities that should support Soft Delete.
import javax.persistence.MappedSuperclass;
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
import java.time.LocalDateTime;
@MappedSuperclass
public abstract class Auditable {
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
private LocalDateTime deletedAt;
@PrePersist
public void prePersist() {
createdAt = LocalDateTime.now();
}
@PreUpdate
public void preUpdate() {
updatedAt = LocalDateTime.now();
}
// Getters and Setters...
}
Step 2: Define an Entity with Soft Delete
Now, let's define an entity that inherits from Auditable to leverage the Soft Delete behavior.
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class BlogPost extends Auditable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
// Getters and Setters...
}